import Config from "../config/Config";
import SnakeHead from "./SnakeHead";
import SnakeNode from "./SnakeNode";
import Food, { FoodType } from "../world/Food";
import { RandUtil } from "../util/RandUtil";
import Timer from "../../core/Timer";
import World from "../world/World";
import PlayerSnake from "./PlayerSnake";
import { Util } from "../util/Util";
import { IMsgKill, IMsgWall, MsgType } from "../world/Msg";
import { GameEvent } from "../event/GameEvent";

/** 全局参数 */
const cfg = Config.snake
const key_respawn = "snake_respawn"
const ru = RandUtil
const util = Util
const et = GameEvent.Type

/** 蛇类参数接口 */
export interface ISnake {
    /** 所在世界 */
    world: World,
    /** 名称 */
    name?: string
}

/** 生成参数接口 */
export interface ISpawn {
    /** 坐标x */
    x?: number,
    /** 坐标y */
    y?: number,
    /** 角度 */
    ang?: number,
    /** 分数 */
    score?: number,
    /** 颜色 */
    colors?: string[],
}


/** 蛇类 */
export default class Snake {

    /** 所在世界 */
    readonly world: World
    /** 得分排名 */
    rank: number
    /** 唯一标识 */
    protected _id: number
    /** 头部id */
    protected _hid: number
    /** 头部节点 */
    protected _head: SnakeHead
    /** 节点集合 */
    protected _nodes: SnakeNode[] = []
    /** 得分 */
    protected _score: number = 0
    /** 名称 */
    protected _name: string
    /** 死亡状态 */
    protected _isDeath: boolean = true
    /** 重生状态 */
    protected _isSpawning: boolean = false
    /** 颜色 */
    protected _colors: string[] = []
    /** 颜色整型 */
    protected _rgbs: number[] = []
    /** 撞到的物体 */
    protected _collsion: any
    /** 上一个击杀者 */
    protected _killer: Snake
    /** 复仇集合 */
    protected _killers = new Map<Snake, number>()
    /** 击杀数 */
    protected _killCount: number = 0
    /** 计时器 */
    protected _timer = new Timer()

    constructor(obj: ISnake) {
        this.world = obj.world
        this._id = obj.world.getNewSnakeId()
        this._name = obj.name || cfg.initName
    }

    /** 生成 */
    spawn(obj: ISpawn = {}) {

        this._isDeath = false
        this._isSpawning = false
        this._score = obj.score || 0
        this._colors = obj.colors
        if (!this._colors) {
            this._colors = [ru.randColor()]
            while (ru.chance(0.25)) {
                this._colors.push(ru.randColor())
            }
        }
        this._rgbs = []
        this._colors.forEach(color => this._rgbs.push(util.color2rgb(color)))

        this.clearNode()
        let { x, y } = this.world.getSpawnPos()
        //生成头部节点
        this._head = new SnakeHead({
            world: this.world,
            x: obj.x || x,
            y: obj.y || y,
            ang: obj.ang || ru.rand(0, 360),
            w: cfg.initWidth,
            owner: this
        });
        this._hid = this._head.id
        this._nodes.push(this._head)
        ///生成身体节点
        for (let i = cfg.initLen - 1; i >= 0; i--) {
            this.addNode();
        }
        this.ed.send(et.SNAKE_SPAWN, { snake: this })
    }

    /** 每帧执行 */
    update() {
        if (!this._isDeath) {
            this._nodes.forEach(n => n.update())
            this.grow();
        }
    }

    /** 移动后执行 */
    updateAfterMove() {
        if (!this._isDeath) {
            this.collideCheck();
        }
    }

    /** 碰撞检测后执行 */
    updateAfterCheck() {
        if (!this._isDeath) {
            this.collide();
        } else {
            this.respawn()
        }
    }

    /** 增长节点 */
    addNode() {
        this._nodes.push(SnakeNode.create(this.tail));
    }

    /** 缩短节点 */
    popNode() {
        this._nodes.pop().destory()
    }

    /** 清空节点 */
    clearNode() {
        for (let i = this._nodes.length; i--;) {
            this.popNode()
        }
    }

    /** 成长 */
    private grow() {
        let w = this.getWidth()
        this._nodes.forEach(n => n.setWidth(w));
        let len = this.getNodeCount() - this._nodes.length;

        while (len > 0) {
            len--;
            this.addNode();
        }
        while (len < 0) {
            len++;
            this.popNode();
        }
    }

    /** 碰撞检测 */
    private collideCheck() {
        this._collsion = this._head.collideCheck();
    }

    /** 碰撞 */
    private collide() {
        if (this._collsion) {
            this.die(this._collsion)
            this._collsion = null;
        }
    }

    /** 死亡 */
    die(killer: any) {
        this._timer.set(key_respawn, cfg.respawnTime)
        this._isDeath = true;
        //设置生成战利品食物的总分
        let score = (ru.rand2(cfg.deathScore) + this._score / 2.33) / this._nodes.length;
        this._nodes.forEach(node => {
            //食物浮动范围
            let range = node.w / 3.33
            //生成战利品食物
            this.world.addFood(Food.create({
                world: this.world,
                x: ru.rand(node.x - range, node.x + range),
                y: ru.rand(node.y - range, node.y + range),
                color: this._colors[node.idx % this._colors.length],
                score: ru.rand(score * 0.66, score * 1.66),
                type: FoodType.snake,
            }))
        })
        this.clearNode();
        //传递击杀消息
        if (killer instanceof Snake) {
            //被蛇击杀
            this._killer = killer
            this._killer._killCount++;
            this._killers.set(this._killer, (this._killers.get(this._killer) || 0) + 1);
            this.world.addMsg<IMsgKill>({
                type: MsgType.kill,
                data: {
                    snakeId: this.id,
                    killerId: killer.id
                }
            })
        } else {
            //撞墙
            this.world.addMsg<IMsgWall>({
                type: MsgType.wall,
                data: {
                    snakeId: this.id,
                }
            })
        }
        this.ed.send(et.SNAKE_DIE, { snake: this })
    }

    /** 重生 */
    private respawn() {
        this._timer.check(key_respawn, () => {
            this.spawn()
            this.ed.send(et.SNAKE_SPAWN, { snake: this })
        })
    }



    // ================================================================


    /** 唯一标识 */
    get id() { return this._id }

    /** 头部id */
    get hid() { return this._hid }

    /** 名称 */
    get name() { return this._name }

    /** 头部节点 */
    get head() { return this._head }

    /** 死亡状态 */
    get isDeath() { return this._isDeath }

    /** 颜色 */
    get colors() { return this._colors }

    /** 颜色整型 */
    get rgbs() { return this._rgbs }

    /** 尾部节点 */
    get tail() { return this._nodes[this._nodes.length - 1] }

    /** 得分 */
    get score() { return this._score }
    set score(v: number) { this._score = Math.max(0, v) }

    /** 游戏事件 */
    get ed() { return this.world.ed }

    /** 能看到当前蛇的玩家集合 */
    getCanLookedPlayers() {
        let players: PlayerSnake[] = []
        this.world.playerMap.forEach(player => {
            if (player.screenChunks.some(chunk => chunk.snakes.some(snake => snake == this))) {
                players.push(player)
            }
        })
        return players
    }

    /** 体型宽度 */
    getWidth() {
        return cfg.initWidth + Math.pow(this._score, 0.33);
    }

    /** 节点个数 */
    getNodeCount() {
        let count = this._score / this._head.w
        if (count > 100) {
            count = 100 + Math.max(0, count - 100) / 1.1
            if (count > 200) {
                count = 200 + Math.max(0, count - 200) / 1.23
                if (count > 300) {
                    count = 300 + Math.max(0, count - 300) / 1.33
                    if (count > 666) {
                        count = 666 + Math.max(0, count - 666) / 6.66
                        if (count > 888) {
                            count = 888 + Math.max(0, count - 888) / 8.88
                        }
                    }
                }
            }
        }
        return cfg.initLen + Math.floor(count);
    }

    /** 蛇长度米数 */
    getMeter() {
        return Math.floor(this._nodes.length * this._head.r);
    }
}